﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SmartMathLibrary.LinearEquationSolvers;

namespace SmartMathLibrary.LinearEquationSolvers
{
    /// <summary>
    /// This class provides methods to solve a complex linear system by using the Jacobi method.
    /// </summary>
    [Serializable]
    public class JacobiComplexLinearSystemSolver : AbstractComplexSplittingMethod
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="JacobiComplexLinearSystemSolver"/> class.
        /// </summary>
        /// <param name="coefficientMatrix">The coefficient matrix to solve.</param>
        /// <param name="resultVector">The result vector of the equation system to solve.</param>
        public JacobiComplexLinearSystemSolver(ComplexMatrix coefficientMatrix, GeneralComplexVector resultVector)
            : base(coefficientMatrix, resultVector)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="JacobiComplexLinearSystemSolver"/> class.
        /// </summary>
        /// <param name="equationSystem">The system of equation to solve.</param>
        public JacobiComplexLinearSystemSolver(ComplexLinearEquationSystem equationSystem)
            : base(equationSystem)
        {
        }

        /// <summary>
        /// Solves the linear system, which is defined by the coefficient matrix by using the
        /// Jacobi method. Check if the system of equations converge, otherwise the calculated
        /// results are wrong.
        /// </summary>
        /// <returns>
        /// The solved linear system in form of a vector.
        /// </returns>
        public override GeneralComplexVector SolveLinearSystem()
        {
            return this.SolveLinearSystem(new GeneralComplexVector(this.CoefficientMatrix.Rows), 100, 1e-15);
        }

        /// <summary>
        /// Solves the linear system, which is defined by the coefficient matrix by using the
        /// Jacobi method. Check if the system of equations converge, otherwise the calculated
        /// results are wrong.
        /// </summary>
        /// <param name="startValues">The start values of the calculation in form of a vector.</param>
        /// <returns>
        /// The solved linear system in form of a vector.
        /// </returns>
        public override GeneralComplexVector SolveLinearSystem(GeneralComplexVector startValues)
        {
            return this.SolveLinearSystem(startValues, 100, 1e-15);
        }

        /// <summary>
        /// Solves the linear system, which is defined by the coefficient matrix by using the
        /// Jacobi method. Check if the system of equations converge, otherwise the calculated
        /// results are wrong.
        /// </summary>
        /// <param name="startValues">The start values of the calculation in form of a vector.</param>
        /// <param name="maxIterations">The maximum of iterations for the calculation.</param>
        /// <returns>
        /// The solved linear system in form of a vector.
        /// </returns>
        public override GeneralComplexVector SolveLinearSystem(GeneralComplexVector startValues, int maxIterations)
        {
            return this.SolveLinearSystem(startValues, maxIterations, 1e-15);
        }

        /// <summary>
        /// Solves the linear system, which is defined by the coefficient matrix by using the 
        /// Jacobi method. Check if the system of equations converge, otherwise the calculated
        /// results are wrong.
        /// </summary>
        /// <param name="startValues">The start values of the calculation in form of a vector.</param>
        /// <param name="maxIterations">The maximum of iterations for the calculation.</param>
        /// <param name="precision">The precision of the results to calculate.</param>
        /// <returns>The solved linear system in form of a vector.</returns>
        public override GeneralComplexVector SolveLinearSystem(GeneralComplexVector startValues, int maxIterations,
                                                               double precision)
        {
            ComplexToRealLinearSystemTransform complexTransform =
                new ComplexToRealLinearSystemTransform(new ComplexLinearEquationSystem(this.CoefficientMatrix,
                                                                                       this.ResultVector));
            JacobiLinearSystemSolver jacobiSolver =
                new JacobiLinearSystemSolver(complexTransform.TransformToRealEquationSystem());
            GeneralVector result =
                jacobiSolver.SolveLinearSystem(GeneralVector.UnionVectors(startValues.ExtractRealNumberPartVector(),
                                                                          startValues.ExtractImaginaryNumberPartVector()));

            this.SetPrecisionError(jacobiSolver.PrecisionError);

            return AbstractComplexSplittingMethod.AmalgamateComplexVector(result);
        }
    }
}